using System;
using System.ComponentModel.Design;
using System.Reflection;
using System.Windows.Forms;
using Microsoft.WowAddonStudio.FrameXml.Components;
using Microsoft.WowAddonStudio.FrameXml.Components.Layout;
using Microsoft.WowAddonStudio.FrameXml.Components.Tests;
using Microsoft.WowAddonStudio.FrameXml.Editor.Test.Mocks;
using Microsoft.WowAddonStudio.FrameXml.Editor.ToolWindows;
using Microsoft.WowAddonStudio.FrameXml.Serialization;
using Microsoft.WowAddonStudio.FrameXml.Serialization.LayoutFrames;
using Microsoft.WowAddonStudio.Tests.Common.Mocks;

using NUnit.Framework;
using Button=Microsoft.WowAddonStudio.FrameXml.Serialization.LayoutFrames.Button;

namespace Microsoft.WowAddonStudio.FrameXml.Editor.Test
{
	[TestFixture]
	public sealed class LayoutControlManagerTest : FrameXmlControlTestBase
	{
		private IDesignerHost designerHost;
		private readonly SimpleTestServiceLocator locator = new SimpleTestServiceLocator();
		private LayoutControlManager manager;
		private LayoutControllerToolWindow toolWindow;

		#region SetUp

		[TestFixtureSetUp]
		public override void SetUp()
		{
			base.SetUp();
			SimpleTestServiceLocator.Register(new FrameXmlLayoutEngine());
			SimpleTestServiceLocator.Register(new MockComponentChangeService());

			UiControl rootControl = frameXmlComponentFactory.CreateComponent<Ui, UiControl>(new Ui());

			rootControl.Controls.Add(CreateTestControl());
			rootControl.Controls[0].Name = "TestControl1";
			rootControl.Controls.Add(CreateTestControl());
			rootControl.Controls[1].Name = "TestControl2";
			//$Controls->Ui->TestControl1
			//			   ->TestControl2
			//			   ->TestControl3->TestControl4->TestControl5
			//							 ->TestControl6
			var controlWithChild = CreateTestControl();
			var controlWithOneChild = CreateTestControl();

			controlWithOneChild.Controls.Add(CreateTestControl());
			controlWithOneChild.Controls[0].Name = "TestControl5";

			controlWithChild.Controls.Add(controlWithOneChild);
			controlWithChild.Controls[0].Name = "TestControl4";


			controlWithChild.Controls.Add(CreateTestControl());
			controlWithChild.Controls[1].Name = "TestControl6";
			rootControl.Controls.Add(controlWithChild);
			rootControl.Controls[2].Name = "TestControl3";

			toolWindow = new LayoutControllerToolWindow(locator);
			SimpleTestServiceLocator.Register(toolWindow);
			//Call protected Initialize() method.
			toolWindow.GetType().GetMethod("Initialize", BindingFlags.NonPublic | BindingFlags.Instance)
				.Invoke(toolWindow, BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance, null, null, null);

			designerHost = new MockDesignerHost(locator, rootControl);
			SimpleTestServiceLocator.Register(designerHost);
			manager = new LayoutControlManager(locator);
		}

		#endregion

		#region TearDown

		[TearDown]
		public override void TearDown()
		{
			base.TearDown();
			SimpleTestServiceLocator.Reset();
		}

		#endregion

		#region Tests

		[Test(Description = "")]
		public void Test_FindParentControl()
		{
			manager.Register(designerHost);

			Control control = manager.FindControl(designerHost.RootComponent as Control, "TestControl4");
			var parent = manager.FindParent(designerHost.RootComponent as Control, control);
			Assert.IsNotNull(parent);
			Console.WriteLine(parent.Name); //TestControl3
			Assert.AreEqual("TestControl3", parent.Name);

			control = manager.FindControl(designerHost.RootComponent as Control, "TestControl5");
			parent = manager.FindParent(designerHost.RootComponent as Control, control);
			Assert.IsNotNull(parent);
			Console.WriteLine(parent.Name); //TestControl4
			Assert.AreEqual("TestControl4", parent.Name);

			control = manager.FindControl(designerHost.RootComponent as Control, "TestControl6");
			parent = manager.FindParent(designerHost.RootComponent as Control, control);
			Assert.IsNotNull(parent);
			Console.WriteLine(parent.Name); //TestControl3
			Assert.AreEqual("TestControl3", parent.Name);

			control = manager.FindControl(designerHost.RootComponent as Control, "TestControl1");
			parent = manager.FindParent(designerHost.RootComponent as Control, control);
			Assert.IsNotNull(parent);
			Console.WriteLine(parent.Name); //TestControl1
			Assert.AreEqual("TestControl1", parent.Name);

			control = manager.FindControl(designerHost.RootComponent as Control, "TestControl3");
			parent = manager.FindParent(designerHost.RootComponent as Control, control);
			Assert.IsNotNull(parent);
			Console.WriteLine(parent.Name); //TestControl3
			Assert.AreEqual("TestControl3", parent.Name);

			control = manager.FindControl(designerHost.RootComponent as Control, "TestControl1");
			parent = manager.FindParent(control);
			Assert.IsNotNull(parent);
			Console.WriteLine(parent.Name); //Ui
			Assert.AreEqual("Ui1", parent.Name);

			control = manager.FindControl(designerHost.RootComponent as Control, "TestControl3");
			parent = manager.FindParent(control);
			Assert.IsNotNull(parent);
			Console.WriteLine(parent.Name); //Ui
			Assert.AreEqual("Ui1", parent.Name);
		}

		[Test(Description = "")]
		public void Test_FindControl()
		{
			FindAndAssertControl("TestControl5");
			FindAndAssertControl("TestControl4");
			FindAndAssertControl("TestControl1");
			FindAndAssertControl("TestControl2");
			FindAndAssertControl("TestControl3");
			FindAndAssertControl("TestControl6");

			Control control = manager.FindControl(designerHost.RootComponent as Control, "XDCDWEFWE");
			Assert.IsNull(control);
		}

		/// <summary>
		/// Finds and asserts control.
		/// </summary>
		/// <param name="name">The name.</param>
		private void FindAndAssertControl(string name)
		{
			Control control = manager.FindControl(designerHost.RootComponent as Control, name);
			Assert.IsNotNull(control);
			Assert.AreEqual(control.Name, name);
		}

		[Test(Description = "")]
		public void Test_ChangeStateControl()
		{
			var window = toolWindow.Window as HierarchicalLayoutControllerHost;
			Assert.IsNotNull(window);
			manager.Register(designerHost);
			Control control = manager.FindControl(designerHost.RootComponent as Control, "TestControl4");
			Assert.IsNotNull(control);
			Assert.AreEqual(control.Name, "TestControl4");
			var frameControl = control as LayoutFrameControl;
			Assert.IsNotNull(frameControl);
			Assert.IsFalse(GetHiddenProperty(frameControl));

			//$Controls->Ui->TestControl3->TestControl4
			window.LayoutTree.Nodes[0].Nodes[0].Nodes[2].Nodes[0].Checked = false;
			Assert.IsTrue(GetHiddenProperty(frameControl));

			frameControl = manager.FindControl(designerHost.RootComponent as Control, "TestControl3") as LayoutFrameControl;
			Assert.IsNotNull(frameControl);
			Assert.IsFalse(GetHiddenProperty(frameControl));
			//$Controls->Ui->TestControl3->
			window.LayoutTree.Nodes[0].Nodes[0].Nodes[2].Checked = false;
			Assert.IsTrue(GetHiddenProperty(frameControl));

			frameControl = manager.FindControl(designerHost.RootComponent as Control, "TestControl5") as LayoutFrameControl;
			Assert.IsNotNull(frameControl);
			Assert.IsFalse(GetHiddenProperty(frameControl));
			//$Controls->Ui->TestControl3->TestControl4->TestControl5
		}

		[Test(Description = "")]
		public void Test_FindTreeNodeFromNodes()
		{
			var treeView = new TreeView();
			var rootNode = treeView.Nodes.Add("Root");
			rootNode.Nodes.Add("Control1").Tag = "Control1";
			var childNode = rootNode.Nodes.Add("Control2");
			childNode.Tag = "Control2";
			childNode.Nodes.Add("Control3").Tag = "Control3";
			rootNode.Nodes.Add("Control4").Tag = "Control4";

			TreeNode findNode = manager.FindNode(rootNode.Nodes, "Control3");	
			Assert.IsNotNull(findNode);
			Assert.AreEqual("Control3", findNode.Text);

			findNode = manager.FindNode(rootNode.Nodes, "Control1");
			Assert.IsNotNull(findNode);
			Assert.AreEqual("Control1", findNode.Text);

			findNode = manager.FindNode(rootNode.Nodes, "Control2");
			Assert.IsNotNull(findNode);
			Assert.AreEqual("Control2", findNode.Text);

			findNode = manager.FindNode(rootNode.Nodes, "Control4");
			Assert.IsNotNull(findNode);
			Assert.AreEqual("Control4", findNode.Text);

			findNode = manager.FindNode(childNode, "Control2");
			Assert.IsNotNull(findNode);
			Assert.AreEqual("Control2", findNode.Text);

			findNode = manager.FindNode(rootNode.Nodes, "ControlXCV");
			Assert.IsNull(findNode);
		}

		#endregion

		#region Private Helpers

		/// <summary>
		/// Gets the hidden property.
		/// </summary>
		/// <param name="frameControl">The frame control.</param>
		/// <returns></returns>
		private static bool GetHiddenProperty(IFrameXmlComponent frameControl)
		{
			var layoutFrame = frameControl.SerializationObject as LayoutFrame;
			if (layoutFrame != null)
			{
				return layoutFrame.Hidden;
			}
			return true;
		}

		/// <summary>
		/// Creates the test control.
		/// </summary>
		/// <returns></returns>
		private LayoutFrameControl CreateTestControl()
		{
			var button = new Button();
			var control = frameXmlComponentFactory.
				CreateComponent<Button, ButtonControl>(button);
			return control;
		}

		#endregion
	}
}